package com.android.fragmentdemo.defineviews
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ViewConfiguration
import android.view.ViewGroup
import androidx.core.view.get
import kotlin.math.abs

class PullToLoadMoreLayout @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : ViewGroup(context, attributeSet) {

    private var downY = 0
    private var totalMovedY = 0
    private var touchSlop = 0

    private var mHeadHeight = 0
    private var mFooterHeight = 0

    private var notInRefreshOrLoadState = true

    private var pullToRefreshStyle: PullToRefreshState = PullToRefreshState.None
    private var pullToRefreshFooter: PullToRefreshFooter? = null
    private var overScrollRecyclerView: DeOverScrollRecyclerView? = null

    private var mPullToRefreshCallback: IPullToRefreshCallback? = null

    init {
        val configuration = ViewConfiguration.get(context)
        touchSlop = configuration.scaledTouchSlop
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        for (i in 0.until(childCount)) {
            val child = get(i)
            when (child) {
                is PullToRefreshFooter -> {
                    pullToRefreshFooter = child
                }
                is DeOverScrollRecyclerView -> {
                    overScrollRecyclerView = child
                }
                else -> {}
            }
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
        }
        setMeasuredDimension(
            MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd,
            MeasureSpec.getSize(heightMeasureSpec) - paddingTop - paddingBottom
        )
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        for (i in 0.until(childCount)) {
            val child = get(i)
            val childWidth = child.measuredWidth
            val childHeight = child.measuredHeight
            when (i) {
                0 -> {
                    child.layout(0, 0, childWidth, childHeight)
                    mHeadHeight = childHeight
                }
                1 -> {
                    child.layout(0, mHeadHeight, childWidth, childHeight + mHeadHeight)
                    mFooterHeight = childHeight
                }
            }
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                downY = ev.y.toInt()
            }
            MotionEvent.ACTION_MOVE -> {
                val moveY = ev.y.toInt()
                val diffY = moveY - downY
                //val condition = abs(diffY) >= touchSlop
                val condition = diffY < 0
                Log.d(TAG, "abs(diffY):${abs(diffY)},touchSlop:${touchSlop}")
                Log.d(TAG,"condition:${condition}")
                Log.d(TAG,"overScrollRV?.inDownOrUp:${overScrollRecyclerView?.positionInDownOrUp() == true}")
                return if (condition && overScrollRecyclerView?.positionInDownOrUp() == true && notInRefreshOrLoadState) {
                    downY = moveY
                    true
                } else {
                    downY = moveY
                    super.onInterceptTouchEvent(ev)
                }
            }
        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        performClick()
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                downY = event.y.toInt()
            }
            MotionEvent.ACTION_MOVE -> {
                val moveY = event.y.toInt()
                val diffY = ((moveY - downY) * FACTOR).toInt()
                totalMovedY += diffY
                scrollTo(0, -totalMovedY)
                downY = moveY
            }
            MotionEvent.ACTION_UP -> {
                if (totalMovedY < 0) {
                    //上拉加载
                    val condition = abs((totalMovedY)) >= mFooterHeight.scale()
                    val scrollY = if (condition) {
                        notInRefreshOrLoadState = false
                        setFooterViewVisibility(true)
                        switchFooterAnimation(true)
                        pullToRefreshStyle = PullToRefreshState.PullUpToLoadMore
                        mPullToRefreshCallback?.pullUpToLoad()
                        -mFooterHeight
                    } else {
                        0
                    }
                    scrollTo(0, -scrollY)
                } else {
                    scrollTo(0, 0)
                }
            }
        }
        return true
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }

    fun setPullToRefreshCallback(mPullToRefreshCallback: IPullToRefreshCallback?) {
        this.mPullToRefreshCallback = mPullToRefreshCallback
    }

    fun resetViewState() {
        totalMovedY = 0
        overScrollRecyclerView?.resetPosition(false)
        scrollTo(0, 0)
        notInRefreshOrLoadState = true
        setHeadOrFooterViewVisibility()
    }

    private fun setFooterViewVisibility(visible: Boolean) {
        pullToRefreshFooter?.setFooterTipVisibility(!visible)
        pullToRefreshFooter?.setFooterLRCVVisibility(visible)
    }

    private fun switchFooterAnimation(flag: Boolean) {
        if (flag) {
            pullToRefreshFooter?.execLoadMoreAnimation()
        } else {
            pullToRefreshFooter?.stopLoadMoreAnimation()
        }
    }

    private fun setHeadOrFooterViewVisibility() {
        when (pullToRefreshStyle) {
            PullToRefreshState.PullUpToLoadMore -> {
                switchFooterAnimation(false)
                setFooterViewVisibility(false)
                Log.d(TAG, "PullToRefreshState.PullUpToLoadMore")
            }
            else -> {}
        }
        pullToRefreshStyle = PullToRefreshState.None
    }

    private fun Int.scale() : Int {
        return this * 5 / 7
    }

    interface IPullToRefreshCallback {
        fun pullDownToRefresh()
        fun pullUpToLoad()
    }

    companion object {
        const val TAG = "PullToLoadMoreLayout"
        const val FACTOR = 0.45F
    }

    sealed class PullToRefreshState {
        data object PullUpToLoadMore : PullToRefreshState()
        data object None : PullToRefreshState()
    }
}